package java3.io;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.TreeMap;

public class UtilLoser {
//    UtilLoser(){}

    public static final int pawn = 1;
    public static final int knight = 2;
    public static final int bishop = 3;
    public static final int rook = 4;
    public static final int queen = 5;
    public static final int king = 6;
    public static final int white = 0;
    public static final int black = 1;
    public static final int vacio = 0;
    public static final int sincolor = 2;
    public static final String spawn = "p";
    public static final String sknight = "n";
    public static final String sbishop = "b";
    public static final String srook = "r";
    public static final String squeen = "q";
    public static final String sking = "k";
    public static final String sPAWN = "P";
    public static final String sKNIGHT = "N";
    public static final String sBISHOP = "B";
    public static final String sROOK = "R";
    public static final String sQUEEN = "Q";
    public static final String sKING = "K";
    private Map<Integer, Object> linea = new TreeMap<>();
    public static int tipoLog = 0;
    public static boolean pintaLog;

    public String imprimirTablero(int[][] posiciones, boolean estavolteado) {

        StringBuilder tablero = new StringBuilder();
        String aux = "";
        int ficha, color, ind;

        for (int i = 0; i < 64; i++) {

            ind = estavolteado ? 63 - i : i;

            ficha = posiciones[0][ind];
            color = posiciones[1][ind];

            switch (ficha) {
                case vacio:
                    aux += "" + "|\t";
                    break;
                case pawn:
                    aux += (color == white ? "P0" : color == black ? "p1" : "X") + "|\t";
                    break;
                case knight:
                    aux += (color == white ? "N" : color == black ? "n" : "X") + "|\t";
                    break;
                case bishop:
                    aux += (color == white ? "B" : color == black ? "b" : "X") + "|\t";
                    break;
                case rook:
                    aux += (color == white ? "R" : color == black ? "r" : "X") + "|\t";
                    break;
                case queen:
                    aux += (color == white ? "Q" : color == black ? "q" : "X") + "|\t";
                    break;
                case king:
                    aux += (color == white ? "K" : color == black ? "k" : "X") + "|\t";
                    break;
            }
            if (estavolteado) {
                if (ind % 8 == 0) {
                    tablero.insert(0, (ind / 8 + 1) + "\t" + aux + "\n");
                    aux = "";
                }
            } else {
                if (ind != 0 && (ind + 1) % 8 == 0) {
                    tablero.insert(0, (ind / 8 + 1) + "\t" + aux + "\n");
                    aux = "";
                }
            }
        }

        if (estavolteado) {
            tablero.append("\t h \t g \t f \t e \t d \t c \t b \t a");
        } else {
            tablero.append("\t a \t b \t c \t d \t e \t f \t g \t h");
        }

        return tablero.toString();
    }

    public int esJaque(int[] amenazas) {
        int pos_jaque = -1;//-1=no hay jaque, 100=doble jaque, otro=pos jaque

        for (int i = 0; i < amenazas.length; i++) {
            if (amenazas[i] > 99) {
                if (pos_jaque == -1) {
                    pos_jaque = amenazas[i] - 100;
                } else {
                    pos_jaque = 100;
                    break;
                }
            }
        }
        return pos_jaque;
    }

    public int esJaque(int[] amenazas, int pos_king) {
        int pos_jaque = -1;//-1=no hay jaque, 100=doble jaque, otro=pos jaque

        for (int i = 0; i < amenazas.length; i++) {
            if (amenazas[i] == pos_king) {
                if (pos_jaque == -1) {
                    pos_jaque = amenazas[i];
                } else {
                    pos_jaque = 100;
                    break;
                }
            }
        }
        return pos_jaque;
    }

    public int devuelvePosicionRey(int[][] tablero, int color) {
        for (int j = 0; j < 64; j++) {
            if (tablero[0][j] == king && tablero[1][j] == color) {
                return j;
            }
        }
        return -1;
    }

    public String imprimirJugadas(List<int[]> jugadas) {

        StringBuilder stb = new StringBuilder();

        for (int[] j : jugadas) {
            stb.append(this.imprimirJugada(j)).append(",");
        }

        return stb.toString();
    }

    public String imprimirJugada(int[] j) {

        StringBuilder stb = new StringBuilder();

        stb.append(this.pos1(j[1]))
                .append(this.pos1(j[2]));
        if (j.length > 3) {
            switch (j[3]) {
                case knight:
                    stb.append("N");
                    break;
                case bishop:
                    stb.append("B");
                    break;
                case rook:
                    stb.append("R");
                    break;
                case queen:
                    stb.append("Q");
                    break;
            }
        }

        return stb.toString();
    }

    public boolean enFila(int pos, int pos_king) {
        int f;
        for (int i = 0; i < 8; i++) {
            f = i * 8;
            if (pos >= f && pos < f + 8
                    && pos_king >= f && pos_king < f + 8) {
                return true;
            }
        }
        return false;
    }

    public boolean enColumna(int pos, int pos_king) {
        if (Math.abs(pos - pos_king) % 8 == 0) {
            return true;
        }
        return false;
    }

    public int[] convertirListtoArray(List<Integer> amenazas) {

        int[] array = new int[amenazas.size()];

        for (int i = 0; i < amenazas.size(); i++) {
            array[i] = amenazas.get(i);
        }

        return array;
    }

    public boolean siArrayContiene(int[] amenazas, int val) {
        for (int j = 0; j < amenazas.length; j++) {
            if (amenazas[j] == val) {
                return true;
            }
        }
        return false;
    }

    private String pos1(int paramInt) {
        String str;

        if (paramInt < 8) {
            str = new StringBuilder().append(pos2(paramInt)).append(1).toString();
        } else {
            str = new StringBuilder().append(pos2(paramInt % 8)).append(paramInt / 8 + 1).toString();
        }

        return str;
    }

    private String pos2(int paramInt) {
        switch (paramInt) {
            case 0:
                return "a";
            case 1:
                return "b";
            case 2:
                return "c";
            case 3:
                return "d";
            case 4:
                return "e";
            case 5:
                return "f";
            case 6:
                return "g";
            case 7:
                return "h";
        }
        return "x";
    }

    public boolean estanEnDiagonal(int x, int y) {

        int factor = 1;
        int val;
        boolean a7 = true,
                b7 = true,
                a9 = true,
                b9 = true;
        do {
            if (a7) {
                val = x - (7 * factor);
                if (val % 8 > 0) {
                    if (val == y) {
                        return true;
                    }
                } else {
                    a7 = false;
                }
            }
            if (b7) {
                val = x + (7 * factor);
                if (val < 64 && val % 8 < 7) {
                    if (val == y) {
                        return true;
                    }
                } else {
                    b7 = false;
                }
            }
            if (a9) {
                val = x - (9 * factor);
                if (val >= 0 && val % 8 < 7) {
                    if (val == y) {
                        return true;
                    }
                } else {
                    a9 = false;
                }
            }
            if (b9) {
                val = x + (9 * factor);
                if (val < 64 && val % 8 > 0) {
                    if (val == y) {
                        return true;
                    }
                } else {
                    b9 = false;
                }
            }
            factor++;
        } while ((a7 || b7 || a9 || b9) && factor < 8);

        return false;
    }

    public int[][] ingresarJugada(int[][] tablero, int[] jugada, boolean esCopia) {

        int[][] _tablero;
        int ficha = jugada[0];
        int ini = jugada[1];
        int fin = jugada[2];
        int prom = jugada.length > 3 ? jugada[3] : 0;

        if (esCopia) {
            _tablero = new int[2][64];
            System.arraycopy(tablero[0], 0, _tablero[0], 0, 64);
            System.arraycopy(tablero[1], 0, _tablero[1], 0, 64);
        } else {
            _tablero = tablero;
        }

        if (ficha == pawn) {
            if (fin > ini) {
                if (ini >= 32 && ini <= 39 && ini + 8 != fin && _tablero[0][fin] == vacio) {
                    _tablero[0][(fin - 8)] = vacio;
                    _tablero[1][(fin - 8)] = sincolor;
                }
            } else if (ini >= 24 && ini <= 31 && ini - 8 != fin && _tablero[0][fin] == vacio) {
                _tablero[0][(fin + 8)] = vacio;
                _tablero[1][(fin + 8)] = sincolor;
            }
        } else if (ficha == king && (ini == 4 || ini == 60)) {
            switch (fin) {
                case 2:
                    _tablero[0][3] = rook;
                    _tablero[1][3] = white;

                    _tablero[0][0] = vacio;
                    _tablero[1][0] = sincolor;
                    break;
                case 6:
                    _tablero[0][5] = rook;
                    _tablero[1][5] = white;

                    _tablero[0][7] = vacio;
                    _tablero[1][7] = sincolor;
                    break;
                case 58:
                    _tablero[0][59] = rook;
                    _tablero[1][59] = black;

                    _tablero[0][56] = vacio;
                    _tablero[1][56] = sincolor;
                    break;
                case 62:
                    _tablero[0][61] = rook;
                    _tablero[1][61] = black;

                    _tablero[0][63] = vacio;
                    _tablero[1][63] = sincolor;
            }
        }

        _tablero[0][fin] = (prom != 0 ? prom : _tablero[0][ini]);
        _tablero[1][fin] = _tablero[1][ini];

        _tablero[0][ini] = vacio;
        _tablero[1][ini] = sincolor;

        return _tablero;
    }

    public boolean[] verificarEnroques(int ficha, int ini, boolean[] oo, boolean isWhite, boolean esCopia) {

        boolean[] enroques = null;

        if (oo[isWhite ? 0 : 2] || oo[isWhite ? 1 : 3]) {
            if (esCopia) {
                enroques = new boolean[4];
                System.arraycopy(oo, 0, enroques, 0, 4);
            } else {
                enroques = oo;
            }

            if (ficha == king) {
                enroques[isWhite ? 0 : 2] = false;
                enroques[isWhite ? 1 : 3] = false;
            } else if (ficha == rook) {
                switch (ini) {
                    case 0:
                    case 56:
                        enroques[isWhite ? 1 : 3] = false;
                        break;
                    case 7:
                    case 63:
                        enroques[isWhite ? 0 : 2] = false;
                        break;
                }
            }
        }

        return enroques == null ? oo : enroques;
    }

    public String convertirJugada(String j) {

        char[] c = j.toCharArray();

        return convnum(new char[]{c[0], c[1]}) + "," + convnum(new char[]{c[2], c[3]});
    }

    public int convnum(char[] c) {
        switch (c[0]) {
            case 'a':
                return 8 * (Character.getNumericValue(c[1]) - 1);
            case 'b':
                return 8 * (Character.getNumericValue(c[1]) - 1) + 1;
            case 'c':
                return 8 * (Character.getNumericValue(c[1]) - 1) + 2;
            case 'd':
                return 8 * (Character.getNumericValue(c[1]) - 1) + 3;
            case 'e':
                return 8 * (Character.getNumericValue(c[1]) - 1) + 4;
            case 'f':
                return 8 * (Character.getNumericValue(c[1]) - 1) + 5;
            case 'g':
                return 8 * (Character.getNumericValue(c[1]) - 1) + 6;
            case 'h':
                return 8 * (Character.getNumericValue(c[1]) - 1) + 7;
        }
        return -1;
    }

    public int valorarTableroDefensivo(int[][] t, int color) {
        int valor = 0;
        int peones = 0;
        int ficha;

        for (int i = 0; i < 64; i++) {
            if (t[1][i] == color) {
                valor = valor + 1;
                ficha = t[0][i];
                if (ficha == pawn) {
                    peones = peones + 1;
                }
            }
        }

        //validando que quede al menos un peón
        if (peones == 0) {
            valor = -1;
        }

        return valor;
    }

    public int valorarTableroAgresivo(int[][] t, int color) {
        int valor = 0;

        for (int i = 0; i < 64; i++) {
            if (t[1][i] == color) {
                valor = valor + 1;
            }
        }

        return valor;
    }

    public boolean valorarTableroPeonAtrapado(int[][] t, int color) {
        int valor = 0;
        boolean espawn = false;

        for (int i = 0; i < 64; i++) {
            if (t[1][i] == color) {
                if (valor < 2) {
                    valor = valor + 1;
                    if (t[0][i] == pawn) {
                        espawn = true;
                    }
                } else {
                    return false;
                }
            }
        }

        return valor == 2 && espawn ? true : false;
    }

    public boolean valorarTableroCompleto(int[][] t) {
        int w = 0;
        int b = 0;
        int color;

        for (int i = 0; i < 64; i++) {
            color = t[1][i];
            if (color == white) {
                w++;
            } else if (color == black) {
                b++;
            }
        }

        return w < 10 || b < 10 ? true : false;
    }

    public List<int[]> ordenarMisJugadas(Jugadas jugadas, int[][] tablero) {

        Map<Integer, int[]> nuevasJugadas = new TreeMap<>();
        List<int[]> peones = new ArrayList<>();
        int ficha;
        int c1 = 0, c2 = 0, c3 = 0, c4 = 0, c5 = 0, c6 = 0;
        boolean esObligatorio = jugadas.isEsObligatorio();
        int fin;

        if (esObligatorio) {
            for (int[] j : jugadas.getJugadas()) {
                fin = j[2];
                switch (tablero[0][fin]) {
                    case vacio:
                    case pawn:
                        nuevasJugadas.put(c1 + 40, j);
                        break;
                    case knight:
                        nuevasJugadas.put(c1 + 30, j);
                        break;
                    case bishop:
                        nuevasJugadas.put(c1 + 20, j);
                        break;
                    case rook:
                        nuevasJugadas.put(c1 + 10, j);
                        break;
                    case queen:
                        nuevasJugadas.put(c1 + 0, j);
                        break;
                }
                c1++;
            }
        } else {
            for (int[] j : jugadas.getJugadas()) {
                ficha = j[0];

                switch (ficha) {
                    case pawn:
                        peones.add(j);
                        break;
                    case knight:
                        nuevasJugadas.put(c2 + 100, j);
                        c2++;
                        break;
                    case king:
                        nuevasJugadas.put(c3 + 200, j);
                        c3++;
                        break;
                    case bishop:
                        nuevasJugadas.put(c4 + 300, j);
                        c4++;
                        break;
                    case queen:
                        nuevasJugadas.put(c5 + 400, j);
                        c5++;
                        break;
                    case rook:
                        nuevasJugadas.put(c6 + 500, j);
                        c6++;
                        break;
                }
            }

            if (!peones.isEmpty()) {
                Collections.shuffle(peones, new Random());
                for (int[] p : peones) {
                    nuevasJugadas.put(c1, p);
                    c1++;
                }
            }
        }

        return new ArrayList<>(nuevasJugadas.values());
    }

    public int[] obtenerJugadadeString(String in, int[][] t) {
        int[] j = new int[4];
        char[] c = in.toCharArray();

        j[1] = this.convnum(new char[]{c[0], c[1]});
        j[2] = this.convnum(new char[]{c[2], c[3]});

        j[0] = t[0][j[1]];

        if (c.length > 4) {
            switch (c[4]) {
                case 'N':
                case 'n':
                    j[3] = knight;
                    break;
                case 'B':
                case 'b':
                    j[3] = bishop;
                    break;
                case 'R':
                case 'r':
                    j[3] = rook;
                    break;
                case 'Q':
                case 'q':
                    j[3] = queen;
                    break;
            }
        }

        return j;
    }

    public String obtenerNotacionFEN(int[][] tablero) {

        StringBuilder stb = new StringBuilder();
        int i;
        int h = 0;
        int ficha;
        int color;

        for (i = 0; i < 64; i++) {
            ficha = tablero[0][i];
            color = tablero[1][i];

            if (color == sincolor) {
                h++;
            } else {
                if (h == 0) {
                    stb.append(devolverPieza(ficha, color));
                } else {
                    stb.append(h).append(devolverPieza(ficha, color));
                    h = 0;
                }
            }
        }

        return stb.toString();
    }

    private String devolverPieza(int ficha, int color) {
        switch (ficha) {
            case pawn:
                return color == white ? sPAWN : spawn;
            case bishop:
                return color == white ? sBISHOP : sbishop;
            case knight:
                return color == white ? sKNIGHT : sknight;
            case rook:
                return color == white ? sROOK : srook;
            case queen:
                return color == white ? sQUEEN : squeen;
            default: //king
                return color == white ? sKING : sking;
        }
    }

    public boolean verificarCaptura(int[][] tablero, int jugador, int rival) {

        int ficha;
        int color;

        for (int i = 0; i < 64; i++) {
            color = tablero[1][i];

            if (color == jugador) {
                ficha = tablero[0][i];

                switch (ficha) {
                    case pawn:
                        switch (color) {
                            case white:
                                if (i % 8 != 0 && tablero[1][i + 7] == rival) {
                                    return true;
                                }
                                if ((i + 1) % 8 != 0 && tablero[1][i + 9] == rival) {
                                    return true;
                                }
                                break;
                            case black:
                                if ((i + 1) % 8 != 0 && tablero[1][i - 7] == rival) {
                                    return true;
                                }
                                if (i % 8 != 0 && tablero[1][i - 9] == rival) {
                                    return true;
                                }
                                break;
                        }
                        break;
                    case knight:
                        //+6 -6
                        if ((i < 56 && i % 8 > 1) && tablero[1][i + 6] == rival) {
                            return true;
                        }
                        if (i > 7 && i % 8 < 6 && tablero[1][i - 6] == rival) {
                            return true;
                        }
                        //+10 -10
                        if (i < 56 && i % 8 < 6 && tablero[1][i + 10] == rival) {
                            return true;
                        }
                        if (i > 7 && i % 8 > 1 && tablero[1][i - 10] == rival) {
                            return true;
                        }
                        //+15 -15
                        if (i < 48 && i % 8 > 0 && tablero[1][i + 15] == rival) {
                            return true;
                        }
                        if (i > 15 && i % 8 < 7 && tablero[1][i - 15] == rival) {
                            return true;
                        }
                        //+17 -17
                        if (i < 48 && i % 8 < 7 && tablero[1][i + 17] == rival) {
                            return true;
                        }
                        if ((i > 15 && i % 8 > 0) && tablero[1][i - 17] == rival) {
                            return true;
                        }
                        break;
                    case bishop:
                        if (this.verificarCapturaDiagonal(tablero, jugador, i, rival, true)) {
                            return true;
                        }
                        break;
                    case rook:
                        if (this.verificarCapturaHorizontalVertical(tablero, jugador, i, rival, true)) {
                            return true;
                        }
                        break;
                    case queen:
                        if (this.verificarCapturaDiagonal(tablero, jugador, i, rival, true)) {
                            return true;
                        }
                        if (this.verificarCapturaHorizontalVertical(tablero, jugador, i, rival, true)) {
                            return true;
                        }
                        break;
                    case king:
                        if (this.verificarCapturaDiagonal(tablero, jugador, i, rival, false)) {
                            return true;
                        }
                        if (this.verificarCapturaHorizontalVertical(tablero, jugador, i, rival, false)) {
                            return true;
                        }
                        break;
                }
            }
        }

        return false;
    }

    private boolean verificarCapturaDiagonal(int[][] tablero, int jugador, int pos, int rival, boolean esRecursivo) {

        int factor = 1;
        int val;
        boolean a7 = true,
                b7 = true,
                a9 = true,
                b9 = true;
        do {
            if (a7) {
                val = pos - (7 * factor);
                if (val % 8 > 0) {
                    if (tablero[1][val] == rival) {
                        return true;
                    } else if (tablero[1][val] == jugador) {
                        a7 = false;
                    }
                } else {
                    a7 = false;
                }
            }
            if (b7) {
                val = pos + (7 * factor);
                if (val < 64 && val % 8 < 7) {
                    if (tablero[1][val] == rival) {
                        return true;
                    } else if (tablero[1][val] == jugador) {
                        b7 = false;
                    }
                } else {
                    b7 = false;
                }
            }
            if (a9) {
                val = pos - (9 * factor);
                if (val >= 0 && val % 8 < 7) {
                    if (tablero[1][val] == rival) {
                        return true;
                    } else if (tablero[1][val] == jugador) {
                        a9 = false;
                    }
                } else {
                    a9 = false;
                }
            }
            if (b9) {
                val = pos + (9 * factor);
                if (val < 64 && val % 8 > 0) {
                    if (tablero[1][val] == rival) {
                        return true;
                    } else if (tablero[1][val] == jugador) {
                        b9 = false;
                    }
                } else {
                    b9 = false;
                }
            }
            factor++;
        } while ((a7 || b7 || a9 || b9) && factor < 8 && esRecursivo);

        return false;
    }

    private boolean verificarCapturaHorizontalVertical(int[][] tablero, int jugador, int pos, int rival, boolean esRecursivo) {
        int factor = 1;
        int val;
        boolean a1 = true,
                b1 = true,
                a8 = true,
                b8 = true;
        do {
            if (a1) {
                val = pos - (1 * factor);
                if (val >= 0 && val % 8 < 7) {
                    if (tablero[1][val] == rival) {
                        return true;
                    } else if (tablero[1][val] == jugador) {
                        a1 = false;
                    }
                } else {
                    a1 = false;
                }
            }
            if (b1) {
                val = pos + (1 * factor);
                if (val % 8 > 0) {
                    if (tablero[1][val] == rival) {
                        return true;
                    } else if (tablero[1][val] == jugador) {
                        b1 = false;
                    }
                } else {
                    b1 = false;
                }
            }
            if (a8) {
                val = pos - (8 * factor);
                if (val >= 0) {
                    if (tablero[1][val] == rival) {
                        return true;
                    } else if (tablero[1][val] == jugador) {
                        a8 = false;
                    }
                } else {
                    a8 = false;
                }
            }
            if (b8) {
                val = pos + (8 * factor);
                if (val < 64) {
                    if (tablero[1][val] == rival) {
                        return true;
                    } else if (tablero[1][val] == jugador) {
                        b8 = false;
                    }
                } else {
                    b8 = false;
                }
            }
            factor++;
        } while ((a1 || b1 || a8 || b8) && factor < 8 && esRecursivo);

        return false;
    }

    public void ingresarJugadaLog(int pos, int[] j, boolean b) {
        linea.put(pos, j);
        if (tipoLog != 0 && b) {
            pintaLog = true;
        }
    }

    public void mostrarLog(int limite, String bol) {
        linea.put(limite + 1, bol);
        if (tipoLog != 0) {
            switch (tipoLog) {
                case 1:
                    linea.put(limite + 1, bol);
                    break;
                case 2:
                    if (bol.equals("true") || bol.equals("xtrue")) {
                        this.imprimirLinea(limite, bol, 2);
                    } else {
                        if (pintaLog) {
                            this.imprimirLinea(limite, bol, 2);
                            pintaLog = false;
                        }
                    }
                    break;
            }
        }
    }

    public void mostrarLog2() {
        if (tipoLog != 0) {
            if (tipoLog == 1) {
                this.imprimirLinea(-1, "true", 1);
            }
            linea.clear();
        }
    }

    private void imprimirLinea(int posi, String esValido, int tipo) {

        Object o;
        int[] j;
        String s;

        switch (tipo) {
            case 1:
                for (int k : linea.keySet()) {
                    o = linea.get(k);

                    if (o instanceof int[]) {
                        j = (int[]) o;
                        System.out.print(this.imprimirJugada(j) + ",");
                    } else {
                        s = (String) o;
                        System.out.print(s + "\n");
                        break;
                    }
                }
                break;
            case 2:
                int cnt = 0;
                for (int k : linea.keySet()) {
                    o = linea.get(k);

                    if (o instanceof int[]) {
                        j = (int[]) o;
                        if (cnt < posi + 1) {
                            System.out.print((cnt % 2 == 0 ? "_" : "") + this.imprimirJugada(j) + ",");
                        } else {
                            break;
                        }
                        cnt++;
                    } else {
                        break;
                    }
                }
                System.out.print(esValido + "\n");
                break;
        }
    }

    public List<int[]> ordenarCapturas(List<int[]> capturas, int[] amenazas) {
        Map<Integer, int[]> nuevasJugadas = new TreeMap<>();
        int ficha;
        int c1 = 0, c2 = 0, c3 = 0, c4 = 0, c5 = 0, c6 = 0;

        for (int[] j : capturas) {
            ficha = j[0];

            switch (ficha) {
                case queen:
                    if (c1 == 0) {
                        nuevasJugadas.put(c1 + 50, j);
                    } else if (this.siArrayContiene(amenazas, j[2])) {
                        nuevasJugadas.put(c1, j);
                    } else {
                        nuevasJugadas.put(c1 + 50, j);
                    }
                    c1++;
                    break;
                case bishop:
                    if (c2 == 0) {
                        nuevasJugadas.put(c2 + 150, j);
                    } else if (this.siArrayContiene(amenazas, j[2])) {
                        nuevasJugadas.put(c2 + 100, j);
                    } else {
                        nuevasJugadas.put(c2 + 150, j);
                    }
                    c2++;
                    break;
                case rook:
                    if (c3 == 0) {
                        nuevasJugadas.put(c3 + 250, j);
                    } else if (this.siArrayContiene(amenazas, j[2])) {
                        nuevasJugadas.put(c3 + 200, j);
                    } else {
                        nuevasJugadas.put(c3 + 250, j);
                    }
                    c3++;
                    break;
                case pawn:
                    if (c4 == 0) {
                        nuevasJugadas.put(c4 + 350, j);
                    } else if (this.siArrayContiene(amenazas, j[2])) {
                        nuevasJugadas.put(c4 + 300, j);
                    } else {
                        nuevasJugadas.put(c4 + 350, j);
                    }
                    c4++;
                    break;
                case knight:
                    if (c5 == 0) {
                        nuevasJugadas.put(c5 + 450, j);
                    } else if (this.siArrayContiene(amenazas, j[2])) {
                        nuevasJugadas.put(c5 + 400, j);
                    } else {
                        nuevasJugadas.put(c5 + 450, j);
                    }
                    c5++;
                    break;
                case king:
                    nuevasJugadas.put(c6 + 500, j);
                    c6++;
                    break;
            }
        }

        return new ArrayList<>(nuevasJugadas.values());
    }

    public List<int[]> ordenarJaque(List<int[]> movimientos, int[][] tablero, int jugador) {
        Map<Integer, int[]> nuevasOrden = new TreeMap<>();
        int ficha;
        int c1 = 0, c2 = 0, c3 = 0, c4 = 0, c5 = 0, c6 = 0;

        for (int[] j : movimientos) {
            ficha = j[0];

            switch (ficha) {
                case queen:
                    nuevasOrden.put(c1, j);
                    c1++;
                    break;
                case bishop:
                    nuevasOrden.put(c2 + 100, j);
                    c2++;
                    break;
                case rook:
                    nuevasOrden.put(c3 + 200, j);
                    c3++;
                    break;
                case pawn:
                    nuevasOrden.put(c4 + 300, j);
                    c4++;
                    break;
                case knight:
                    nuevasOrden.put(c5 + 400, j);
                    c5++;
                    break;
                case king:
                    if (this.verificarOrdenRey(tablero, jugador, j[2])) {
                        nuevasOrden.put(c6 + 500, j);
                    } else {
                        nuevasOrden.put(c6 + 550, j);
                    }
                    c6++;
                    break;
            }
        }

        return new ArrayList<>(nuevasOrden.values());
    }

    public void pintarjugadas(List<int[]> l, int tipo) {
        if (tipoLog == 2) {
            if (tipo == 0) {
                System.out.println("mis_jugadas: for [" + this.imprimirJugadas(l) + "]");
            } else {
                System.out.println("for [" + this.imprimirJugadas(l) + "]");
            }
        }
    }

    private boolean verificarOrdenRey(int[][] tablero, int jugador, int pos) {

        int val;

        val = pos - 1;
        if (val >= 0 && val % 8 < 7 && tablero[1][val] == jugador) {
            return false;
        }

        val = pos + 1;
        if (val % 8 > 0 && tablero[1][val] == jugador) {
            return false;
        }

        val = pos - 7;
        if (val % 8 > 0 && tablero[1][val] == jugador) {
            return false;
        }

        val = pos + 7;
        if (val < 64 && val % 8 < 7 && tablero[1][val] == jugador) {
            return false;
        }

        val = pos - 8;
        if (val >= 0 && tablero[1][val] == jugador) {
            return false;
        }

        val = pos + 8;
        if (val < 64 && tablero[1][val] == jugador) {
            return false;
        }

        val = pos - 9;
        if (val >= 0 && val % 8 < 7 && tablero[1][val] == jugador) {
            return false;
        }

        val = pos + 9;
        if (val < 64 && val % 8 > 0 && tablero[1][val] == jugador) {
            return false;
        }

        return true;
    }

    public List<int[]> ordenarJugadasLocal(List<int[]> jugadas, int[][] tablero,
            int[] amenazas, int[] amenazasrival, int jugador, int pos_king) {
        Map<Integer, int[]> nuevoOrden = new TreeMap<>();
        int ficha, fin;
        int c0 = 0, cx = 100, c1 = 200, c2 = 300, c3 = 400, c4 = 500, c5 = 600, c6 = 700, c7 = 800;

        for (int[] j : jugadas) {
            ficha = j[0];
            fin = j[2];

            switch (ficha) {
                case queen:
                    if (this.siArrayContiene(amenazasrival, fin)) {
                        if (!this.siArrayContieneDoble(amenazas, fin)) {
                            nuevoOrden.put(c0, j);
                            c0++;
                        } else {
                            nuevoOrden.put(cx, j);
                            cx++;
                        }
                    } else {
                        if (this.verificarJaque(tablero, ficha, fin, pos_king)) {
                            nuevoOrden.put(c7, j);
                            c7++;
                        } else {
                            nuevoOrden.put(c1 + 50, j);
                            c1++;
                        }
                    }
                    break;
                case bishop:
                    if (this.siArrayContiene(amenazasrival, fin)) {
                        if (!this.siArrayContieneDoble(amenazas, fin)) {
                            nuevoOrden.put(c0 + 20, j);
                            c0++;
                        } else {
                            nuevoOrden.put(cx + 20, j);
                            cx++;
                        }
                    } else {
                        if (this.verificarJaque(tablero, ficha, fin, pos_king)) {
                            nuevoOrden.put(c7 + 20, j);
                            c7++;
                        } else {
                            nuevoOrden.put(c2 + 50, j);
                            c2++;
                        }
                    }
                    break;
                case rook:
                    if (this.siArrayContiene(amenazasrival, fin)) {
                        if (!this.siArrayContieneDoble(amenazas, fin)) {
                            nuevoOrden.put(c0 + 40, j);
                            c0++;
                        } else {
                            nuevoOrden.put(cx + 40, j);
                            cx++;
                        }
                    } else {
                        if (this.verificarJaque(tablero, ficha, fin, pos_king)) {
                            nuevoOrden.put(c7 + 40, j);
                            c7++;
                        } else {
                            nuevoOrden.put(c3 + 50, j);
                            c3++;
                        }
                    }
                    break;
                case pawn:
                    if (this.siArrayContiene(amenazasrival, fin)) {
                        if (!this.siArrayContiene(amenazas, fin)) {
                            nuevoOrden.put(c0 + 60, j);
                            c0++;
                        } else {
                            nuevoOrden.put(cx + 60, j);
                            cx++;
                        }
                    } else {
                        nuevoOrden.put(c4 + 50, j);
                        c4++;
                    }
                    break;
                case knight:
                    if (this.siArrayContiene(amenazasrival, fin)) {
                        if (!this.siArrayContieneDoble(amenazas, fin)) {
                            nuevoOrden.put(c0 + 80, j);
                            c0++;
                        } else {
                            nuevoOrden.put(cx + 80, j);
                            cx++;
                        }
                    } else {
                        if (this.verificarJaque(tablero, ficha, fin, pos_king)) {
                            nuevoOrden.put(c7 + 60, j);
                            c7++;
                        } else {
                            nuevoOrden.put(c5 + 50, j);
                            c5++;
                        }
                    }
                    break;
                case king:
                    if (this.verificarOrdenRey(tablero, jugador, j[2])) {
                        nuevoOrden.put(c6, j);
                    } else {
                        nuevoOrden.put(c6 + 50, j);
                    }
                    c6++;
                    break;
            }
        }

        return new ArrayList<>(nuevoOrden.values());
    }

    private boolean siArrayContieneDoble(int[] amenazas, int val) {
        int cnt = 0;
        for (int j = 0; j < amenazas.length; j++) {
            if (amenazas[j] == val) {
                if (cnt == 1) {
                    return true;
                } else {
                    cnt++;
                }
            }
        }
        return false;
    }

    public boolean ingresarJugadayVerificarEnroques(int[][] tablero, boolean[] enroques, int[] jugada, boolean isWhite) {

        int ficha = jugada[0];
        int ini = jugada[1];
        int fin = jugada[2];
        int prom = jugada.length > 3 ? jugada[3] : 0;
        int color;

        if (ficha == pawn) {
            if (fin > ini) {
                if (ini >= 32 && ini <= 39 && ini + 8 != fin && tablero[0][fin] == vacio) {
                    tablero[0][(fin - 8)] = vacio;
                    tablero[1][(fin - 8)] = sincolor;
                }
            } else if (ini >= 24 && ini <= 31 && ini - 8 != fin && tablero[0][fin] == vacio) {
                tablero[0][(fin + 8)] = vacio;
                tablero[1][(fin + 8)] = sincolor;
            }
        } else if (ficha == king && (ini == 4 || ini == 60)) {
            if (enroques[isWhite ? 0 : 2] || enroques[isWhite ? 1 : 3]) {
                enroques[isWhite ? 0 : 2] = false;
                enroques[isWhite ? 1 : 3] = false;
            }
            switch (fin) {
                case 2:
                    tablero[0][3] = rook;
                    tablero[1][3] = white;

                    tablero[0][0] = vacio;
                    tablero[1][0] = sincolor;
                    break;
                case 6:
                    tablero[0][5] = rook;
                    tablero[1][5] = white;

                    tablero[0][7] = vacio;
                    tablero[1][7] = sincolor;
                    break;
                case 58:
                    tablero[0][59] = rook;
                    tablero[1][59] = black;

                    tablero[0][56] = vacio;
                    tablero[1][56] = sincolor;
                    break;
                case 62:
                    tablero[0][61] = rook;
                    tablero[1][61] = black;

                    tablero[0][63] = vacio;
                    tablero[1][63] = sincolor;
            }
        } else if (ficha == rook) {
            if (enroques[isWhite ? 0 : 2] || enroques[isWhite ? 1 : 3]) {
                switch (ini) {
                    case 0:
                    case 56:
                        enroques[isWhite ? 1 : 3] = false;
                        break;
                    case 7:
                    case 63:
                        enroques[isWhite ? 0 : 2] = false;
                        break;
                }
            }
        }

        if (tablero[0][fin] == rook) {
            if (enroques[!isWhite ? 0 : 2] || enroques[!isWhite ? 1 : 3]) {
                switch (ini) {
                    case 0:
                    case 56:
                        enroques[!isWhite ? 1 : 3] = false;
                        break;
                    case 7:
                    case 63:
                        enroques[!isWhite ? 0 : 2] = false;
                        break;
                }
            }
        }

        color = tablero[1][ini];
        tablero[0][fin] = (prom != 0 ? prom : tablero[0][ini]);
        tablero[1][fin] = color;

        tablero[0][ini] = vacio;
        tablero[1][ini] = sincolor;

        int cnt = 0;
        for (int i = 0; i < 64; i++) {
            if (tablero[1][i] != sincolor && tablero[1][i] != color) {
                if ((cnt = cnt + 1) > 1) {
                    break;
                }
            }
        }

        return cnt == 1 ? true : false;
    }

    public List<int[]> poblarcache() {
        List temp = new ArrayList<>();
        int[] j;

        if (linea.size() > 1) {
            temp = new ArrayList<>();
            Object o;

            for (int k : linea.keySet()) {
                o = linea.get(k);

                if (o instanceof int[]) {
                    j = (int[]) o;
                    temp.add(j);
                } else {
                    break;
                }
            }
        }

        linea.clear();

        return temp;
    }

    public String mostrarCache(Object[] cachememory) {
        StringBuilder sb = new StringBuilder();
        List<int[]> l;
        int cnt = 1;

        for (Object o : cachememory) {
            if (o instanceof List) {
                l = (List<int[]>) o;
                sb.append(cnt).append(")");
                for (int[] j : l) {
                    sb.append(this.imprimirJugada(j)).append(",");
                }
                sb.append("\n");
                cnt++;
            }
        }

        return sb.toString();
    }

    public boolean verificarJaque(int[][] tablero, int ficha, int pos, int pos_king) {

        switch (ficha) {
            case queen:
                if (this.verificarJaqueDiagonal(tablero, pos, pos_king)) {
                    return true;
                }
                if (this.verificarJaqueHorizontalVertical(tablero, pos, pos_king)) {
                    return true;
                }
                break;
            case bishop:
                if (this.verificarJaqueDiagonal(tablero, pos, pos_king)) {
                    return true;
                }
                break;
            case rook:
                if (this.verificarJaqueHorizontalVertical(tablero, pos, pos_king)) {
                    return true;
                }
                break;
            case knight:
                //+6 -6
                if ((pos < 56 && pos % 8 > 1) && pos + 6 == pos_king) {
                    return true;
                }
                if (pos > 7 && pos % 8 < 6 && pos - 6 == pos_king) {
                    return true;
                }
                //+10 -10
                if (pos < 56 && pos % 8 < 6 && pos + 10 == pos_king) {
                    return true;
                }
                if (pos > 7 && pos % 8 > 1 && pos - 10 == pos_king) {
                    return true;
                }
                //+15 -15
                if (pos < 48 && pos % 8 > 0 && pos + 15 == pos_king) {
                    return true;
                }
                if (pos > 15 && pos % 8 < 7 && pos - 15 == pos_king) {
                    return true;
                }
                //+17 -17
                if (pos < 48 && pos % 8 < 7 && pos + 17 == pos_king) {
                    return true;
                }
                if ((pos > 15 && pos % 8 > 0) && pos - 17 == pos_king) {
                    return true;
                }
                break;
        }

        return false;
    }

    private boolean verificarJaqueDiagonal(int[][] tablero, int pos, int pos_king) {

        int factor = 1;
        int val;
        boolean a7 = true,
                b7 = true,
                a9 = true,
                b9 = true;
        do {
            if (a7) {
                val = pos - (7 * factor);
                if (val % 8 > 0) {
                    if (val == pos_king) {
                        return true;
                    } else if (tablero[0][val] != vacio) {
                        a7 = false;
                    }
                } else {
                    a7 = false;
                }
            }
            if (b7) {
                val = pos + (7 * factor);
                if (val < 64 && val % 8 < 7) {
                    if (val == pos_king) {
                        return true;
                    } else if (tablero[0][val] != vacio) {
                        b7 = false;
                    }
                } else {
                    b7 = false;
                }
            }
            if (a9) {
                val = pos - (9 * factor);
                if (val >= 0 && val % 8 < 7) {
                    if (val == pos_king) {
                        return true;
                    } else if (tablero[0][val] != vacio) {
                        a9 = false;
                    }
                } else {
                    a9 = false;
                }
            }
            if (b9) {
                val = pos + (9 * factor);
                if (val < 64 && val % 8 > 0) {
                    if (val == pos_king) {
                        return true;
                    } else if (tablero[0][val] != vacio) {
                        b9 = false;
                    }
                } else {
                    b9 = false;
                }
            }
            factor++;
        } while ((a7 || b7 || a9 || b9) && factor < 8);

        return false;
    }

    private boolean verificarJaqueHorizontalVertical(int[][] tablero, int pos, int pos_king) {

        int factor = 1;
        int val;
        boolean a1 = true,
                b1 = true,
                a8 = true,
                b8 = true;
        do {
            if (a1) {
                val = pos - (1 * factor);
                if (val >= 0 && val % 8 < 7) {
                    if (val == pos_king) {
                        return true;
                    } else if (tablero[0][val] != vacio) {
                        a1 = false;
                    }
                } else {
                    a1 = false;
                }
            }
            if (b1) {
                val = pos + (1 * factor);
                if (val % 8 > 0) {
                    if (val == pos_king) {
                        return true;
                    } else if (tablero[0][val] != vacio) {
                        b1 = false;
                    }
                } else {
                    b1 = false;
                }
            }
            if (a8) {
                val = pos - (8 * factor);
                if (val >= 0) {
                    if (val == pos_king) {
                        return true;
                    } else if (tablero[0][val] != vacio) {
                        a8 = false;
                    }
                } else {
                    a8 = false;
                }
            }
            if (b8) {
                val = pos + (8 * factor);
                if (val < 64) {
                    if (val == pos_king) {
                        return true;
                    } else if (tablero[0][val] != vacio) {
                        b8 = false;
                    }
                } else {
                    b8 = false;
                }
            }
            factor++;
        } while ((a1 || b1 || a8 || b8) && factor < 8);

        return false;
    }
}
